package com.gcgo.zk;

import org.I0Itec.zkclient.ZkClient;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;

public class ServiceDiscovery {
    private CountDownLatch latch = new CountDownLatch(1);
    private String registryAddress; // 注册中心的地址
    //    private volatile List<String> serviceAddressList;
    //    private volatile List<Integer> serviceTimeList;

    private ConcurrentHashMap<String, String> serviceAddressMap;
    private ConcurrentHashMap<String, Long> serviceTimeMap;

    public ServiceDiscovery(String registryAddress) {
        this.registryAddress = registryAddress;
        ZkClient zk = connectServer();
        watchNode(zk);
        //查询对应的响应时间
        watchTime(zk);
    }

    private void watchTime(ZkClient zk) {
        zk.subscribeChildChanges(ServiceRegistry.BASE_SERVICE + ServiceRegistry.TIME, (path, list) -> {
            /**
             *path:监听路径
             * list:当前变化后的children集合
             */
            System.out.println("服务节点发生了变化。。。正在更新响应时间。。");
            watchTime(zk);
        });
        List<String> nodeTimeList = zk.getChildren(ServiceRegistry.BASE_SERVICE + ServiceRegistry.TIME);
        //        List<Integer> dataList = new ArrayList<>();
        ConcurrentHashMap<String, Long> dataMap = new ConcurrentHashMap<>();
        for (String node : nodeTimeList) {
            Long time = zk.readData(ServiceRegistry.BASE_SERVICE + ServiceRegistry.TIME + "/" + node);
            //            dataList.add(address);
            dataMap.put(node, time);
            //监听响应时间的变化
            zk.subscribeChildChanges(ServiceRegistry.BASE_SERVICE + ServiceRegistry.TIME + "/" + node, (path, list) -> {
                System.out.println("响应时间发生了变化。。。正在更新响应时间。。");
                watchTime(zk);
            });
        }
        //        this.serviceTimeList = dataList;
        this.serviceTimeMap = dataMap;
    }

    private void watchNode(ZkClient zk) {
        zk.subscribeChildChanges(ServiceRegistry.BASE_SERVICE + ServiceRegistry.CHILDREN, (path, list) -> {
            /**
             *path:监听路径
             * list:当前变化后的children集合
             */
            System.out.println("服务节点发生了变化。。。正在更新。。");
            watchNode(zk);
        });
        List<String> nodeList = zk.getChildren(ServiceRegistry.BASE_SERVICE + ServiceRegistry.CHILDREN);
        //        List<String> dataList = new ArrayList<>();
        ConcurrentHashMap<String, String> dataMap = new ConcurrentHashMap<>();
        for (String node : nodeList) {
            String address = zk.readData(ServiceRegistry.BASE_SERVICE + ServiceRegistry.CHILDREN + "/" + node);
            //            dataList.add(address);
            dataMap.put(node, address);
        }
        System.out.println("获得服务节点：" + dataMap);
        //        this.serviceAddressList = dataList;
        this.serviceAddressMap = dataMap;
    }

    private ZkClient connectServer() {
        return new ZkClient(registryAddress);
    }

    public String discover() {
        String data = null;
        if (serviceAddressMap.size() == 1) {
            //只有一个服务器
            for (Map.Entry<String, String> entry : serviceAddressMap.entrySet()) {
                data = entry.getKey() + ":" + entry.getValue();//c00000001:127.0.0.1:9997
            }
        } else {
            //负载均衡：先比较时间
            String address = null;
            long time = Long.MAX_VALUE;
            for (Map.Entry<String, Long> entry : serviceTimeMap.entrySet()) {
                long time1 = entry.getValue();
                if (time1 < time) {
                    time = time1;
                    address = entry.getKey();
                } else if (time1 == time) {
                    int i = ThreadLocalRandom.current().nextInt(2);
                    if (i == 1) {//随机选一个服务器
                        //                        time = time1;
                        address = entry.getKey();
                    }
                }
            }
            assert address != null;
            data = address + ":" + serviceAddressMap.get(address);
        }
        System.out.println("选择了服务提供方：" + data);
        return data;
    }
}
